package com.getpebble.android.main.sections.support;

import android.accounts.Account;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources;
import android.net.Uri;
import android.os.Build;
import android.os.Build.VERSION;
import android.os.Environment;
import com.getpebble.android.PebbleApplication;
import com.getpebble.android.R;
import com.getpebble.android.common.auth.PblSessionManager;
import com.getpebble.android.common.core.async.PblAsyncTask;
import com.getpebble.android.common.core.trace.AndroidLogger;
import com.getpebble.android.common.core.trace.Trace;
import com.getpebble.android.common.core.util.PblPreferences;
import com.getpebble.android.common.core.util.PblPreferences.PrefKey;
import com.getpebble.android.common.core.util.ProcessUtil.PebbleProcess;
import com.getpebble.android.common.model.FrameworkState;
import com.getpebble.android.common.model.FrameworkState.EventType;
import com.getpebble.android.common.model.PblDeviceModel.PblDeviceRecord;
import com.getpebble.android.common.model.PblInstalledAppDataModel;
import com.getpebble.android.common.model.PreferenceModel;
import com.getpebble.android.common.util.FileUtil;
import com.getpebble.android.common.util.FileUtil.FileFoundCallback;
import com.getpebble.android.config.BootConfig;
import com.getpebble.android.framework.FrameworkEventReceiver;
import com.getpebble.android.framework.FrameworkEventReceiver.IFrameworkEventListener;
import com.getpebble.android.framework.PblFrameworkInterface;
import com.getpebble.android.framework.endpoint.CoreDumpEndpoint.CoreDumpResult;
import com.getpebble.android.framework.endpoint.LogDumpEndpoint.Result;
import com.getpebble.android.framework.firmware.FirmwareManifestBundle.ReleaseType;
import com.getpebble.android.notifications.util.NotificationUtil;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.regex.Pattern;
import java.util.zip.GZIPOutputStream;

public class SupportEmail {
    static final Pattern PATTERN_LOG_ENTRY_WITH_TIMESTAMP = Pattern.compile("[0-9]+-[0-9]+-[0-9]+\\W[0-9]+:[0-9]+:[0-9]+\\.[0-9]+.+?");
    private static final String TAG = SupportEmail.class.getSimpleName();
    private String mAccountId;
    private AndroidInfo mAndroidInfo;
    private BootConfig mBootConfig;
    private boolean mComplete = false;
    private final Context mContext;
    private String mCoreDumpFilename;
    Boolean mHasCoreDump = null;
    Boolean mHasLogDump = null;
    private Boolean mHasSupportAttachmentUri = null;
    private boolean mIncludeLogs = true;
    private PblDeviceRecord mLastDeviceRecord;
    private String mLogDumpFilename;
    private final Callback mOnComplete;
    private PebbleAndroidInfo mPebbleAndroidInfo;
    private Resources mResources;
    private boolean mSent = false;
    private Uri mSupportAttachmentUri;

    public static class AndroidInfo {
        public final String androidOsVersion;
        public final int androidSdkVersion;
        public final String deviceBrand;
        public final String deviceKernel;
        public final String deviceManufacturer;
        public final String deviceModel;

        public AndroidInfo() {
            this.deviceModel = "";
            this.deviceManufacturer = "";
            this.deviceBrand = "";
            this.deviceKernel = "";
            this.androidOsVersion = "";
            this.androidSdkVersion = 0;
        }

        public AndroidInfo(String deviceModel, String deviceManufacturer, String deviceBrand, String deviceKernel, String androidOsVersion, int androidSdkVersion) {
            this.deviceModel = deviceModel;
            this.deviceManufacturer = deviceManufacturer;
            this.deviceBrand = deviceBrand;
            this.deviceKernel = deviceKernel;
            this.androidOsVersion = androidOsVersion;
            this.androidSdkVersion = androidSdkVersion;
        }
    }

    private class BasicInfoAsyncTask extends PblAsyncTask {
        private BasicInfoAsyncTask() {
        }

        public boolean doInBackground() {
            Trace.verbose(TAG, "BasicInfoAsyncTask doInBackground()");
            AndroidInfo info = SupportEmail.this.generateAndroidInfo();
            BootConfig bootConfig = SupportEmail.this.loadBootConfigInfo();
            PblDeviceRecord lastDeviceRecord = SupportEmail.this.loadLastConnectedDeviceRecord();
            Resources resources = SupportEmail.this.mContext.getResources();
            PebbleAndroidInfo pebbleAndroidInfo = SupportEmail.generatePebbleAndroidInfo(SupportEmail.this.mContext);
            PblSessionManager sessionManager = PebbleApplication.getSessionManager();
            Account account = sessionManager != null ? sessionManager.getUserAccount() : null;
            String userId = account != null ? sessionManager.getId(account) : "";
            synchronized (SupportEmail.this) {
                SupportEmail.this.mAndroidInfo = info;
                SupportEmail.this.mBootConfig = bootConfig;
                SupportEmail.this.mLastDeviceRecord = lastDeviceRecord;
                SupportEmail.this.mResources = resources;
                SupportEmail.this.mPebbleAndroidInfo = pebbleAndroidInfo;
                SupportEmail.this.mAccountId = userId;
                SupportEmail.this.mComplete = SupportEmail.this.isComplete();
            }
            return true;
        }

        public void onTaskSuccess() {
            if (SupportEmail.this.mIncludeLogs) {
                SupportEmail.this.fetchLogDump();
            } else {
                SupportEmail.this.onTaskComplete();
            }
        }

        public void onTaskFailed() {
            if (SupportEmail.this.mIncludeLogs) {
                SupportEmail.this.fetchLogDump();
            } else {
                SupportEmail.this.onTaskComplete();
            }
        }
    }

    public static abstract class Callback {
        public abstract void onComplete(SupportEmail supportEmail);

        public abstract void onPing();
    }

    private class CreateSupportAttachmentAsyncTask extends PblAsyncTask {
        private CreateSupportAttachmentAsyncTask() {
        }

        public boolean doInBackground() {
            File file = SupportEmail.createSupportAttachment(SupportEmail.this.mContext, SupportEmail.this.getSummary(), SupportEmail.this.mIncludeLogs, SupportEmail.this.mAccountId, SupportEmail.this.mOnComplete);
            if (file == null) {
                return false;
            }
            SupportEmail.this.mSupportAttachmentUri = Uri.fromFile(file);
            return true;
        }

        public void onTaskSuccess() {
            synchronized (SupportEmail.this) {
                SupportEmail.this.mHasSupportAttachmentUri = Boolean.valueOf(true);
                SupportEmail.this.mComplete = SupportEmail.this.isComplete();
            }
            SupportEmail.this.onTaskComplete();
        }

        public void onTaskFailed() {
            synchronized (SupportEmail.this) {
                SupportEmail.this.mHasSupportAttachmentUri = Boolean.valueOf(false);
                SupportEmail.this.mComplete = SupportEmail.this.isComplete();
            }
            SupportEmail.this.onTaskComplete();
        }
    }

    public static class PebbleAndroidInfo {
        public final String appVersion;
        public final boolean areNotificationsEnabled;
        public final String releaseChannel;

        public PebbleAndroidInfo(String releaseChannel, String appVersion, boolean areNotificationsEnabled) {
            this.releaseChannel = releaseChannel;
            this.appVersion = appVersion;
            this.areNotificationsEnabled = areNotificationsEnabled;
        }

        public String toString() {
            return "releaseChannel = " + this.releaseChannel + " appVersion = " + this.appVersion + " areNotificationsEnabled = " + this.areNotificationsEnabled;
        }
    }

    public SupportEmail(Context context, boolean includeLogs, Callback onComplete) {
        this.mContext = context;
        this.mIncludeLogs = includeLogs;
        this.mOnComplete = onComplete;
        new BasicInfoAsyncTask().submit();
    }

    public synchronized Intent generateIntent() {
        Intent emailIntent;
        emailIntent = new Intent("android.intent.action.SEND_MULTIPLE");
        emailIntent.setType("plain/text");
        emailIntent.putExtra("android.intent.extra.EMAIL", new String[]{getEmailAddress()});
        emailIntent.putExtra("android.intent.extra.SUBJECT", getSubject());
        emailIntent.putExtra("android.intent.extra.TEXT", getBody());
        ArrayList<Uri> attachmentUris = getAttachmentUris();
        if (this.mSupportAttachmentUri != null && isExternalStorageWritable()) {
            attachmentUris.add(this.mSupportAttachmentUri);
        }
        if (!attachmentUris.isEmpty()) {
            attachmentUris.trimToSize();
            Trace.debug(TAG, "Adding support email attachments, size " + attachmentUris.size());
            emailIntent.putParcelableArrayListExtra("android.intent.extra.STREAM", attachmentUris);
        }
        return emailIntent;
    }

    private AndroidInfo generateAndroidInfo() {
        return new AndroidInfo(Build.MODEL, Build.MANUFACTURER, Build.BRAND, System.getProperty("os.version"), VERSION.RELEASE, VERSION.SDK_INT);
    }

    private BootConfig loadBootConfigInfo() {
        return PebbleApplication.getBootConfig();
    }

    private PblDeviceRecord loadLastConnectedDeviceRecord() {
        PblDeviceRecord pblDeviceRecord = PebbleApplication.getConnectedDeviceRecord();
        if (pblDeviceRecord != null) {
            return pblDeviceRecord;
        }
        Trace.warning(TAG, "No last connected device found");
        return PblDeviceRecord.getEmptyRecord();
    }

    public static PebbleAndroidInfo generatePebbleAndroidInfo(Context context) {
        String releaseChannel;
        String appVersion;
        if (context != null) {
            releaseChannel = new PblPreferences(context).getStringData(PrefKey.RELEASE_CHANNEL, ReleaseType.UNKNOWN.getPath());
            try {
                appVersion = context.getPackageManager().getPackageInfo(context.getPackageName(), 0).versionName;
            } catch (NameNotFoundException e) {
                Trace.warning(TAG, "Failed to find package name", e);
                appVersion = "unknown";
            }
        } else {
            Trace.warning(TAG, "Null context");
            releaseChannel = "unknown";
            appVersion = "unknown";
        }
        return new PebbleAndroidInfo(releaseChannel, appVersion, NotificationUtil.isServiceEnabled(context));
    }

    private boolean isComplete() {
        return this.mComplete || !(this.mAndroidInfo == null || this.mPebbleAndroidInfo == null || this.mBootConfig == null || this.mLastDeviceRecord == null || this.mResources == null || this.mAccountId == null || this.mHasSupportAttachmentUri == null || ((this.mHasCoreDump == null && this.mIncludeLogs) || (this.mHasLogDump == null && this.mIncludeLogs)));
    }

    private synchronized void onTaskComplete() {
        if (this.mComplete && !this.mSent) {
            this.mOnComplete.onComplete(this);
            this.mSent = true;
        }
    }

    private void sendPing() {
        this.mOnComplete.onPing();
    }

    private String getEmailAddress() {
        String supportEmailAddress = this.mBootConfig.getSupportRequestEmailAddress();
        if (supportEmailAddress != null) {
            return supportEmailAddress;
        }
        Trace.warning(TAG, "Support email address not found in boot config, using fallback");
        return this.mResources.getString(R.string.support_email_address);
    }

    private String getSubject() {
        boolean isValidDeviceName;
        StringBuilder subject = new StringBuilder();
        if (this.mBootConfig.getSupportRequestSubject() == null) {
            Trace.warning(TAG, "Support email subject not found in boot config, using fallback");
            subject.append(this.mResources.getString(R.string.support_default_email_subject));
        }
        if (this.mLastDeviceRecord == null || this.mLastDeviceRecord.pblDevice == null || this.mLastDeviceRecord.pblDevice.getName() == null) {
            isValidDeviceName = false;
        } else {
            isValidDeviceName = true;
        }
        if (isValidDeviceName) {
            String friendlyName = this.mLastDeviceRecord.pblDevice.getName();
            subject.append(String.format(" - %s", new Object[]{friendlyName}));
        }
        return subject.toString();
    }

    private String getBody() {
        String emailBodyLanguageWarning = this.mResources.getString(R.string.support_email_language_warning);
        String emailIntro = this.mResources.getString(R.string.support_email_body);
        return emailBodyLanguageWarning + "\n\n" + emailIntro + String.format(this.mResources.getString(R.string.support_email_key_account_body), new Object[]{this.mAccountId, getSummary()});
    }

    private String getSummary() {
        StringBuilder summary = new StringBuilder();
        Gson gson = new GsonBuilder().setPrettyPrinting().create();
        if (this.mAndroidInfo != null) {
            summary.append("Android Info:\n\n");
            summary.append(gson.toJson(this.mAndroidInfo)).append("\n\n");
        }
        if (this.mPebbleAndroidInfo != null) {
            summary.append("Pebble-Android Info:\n\n");
            summary.append(gson.toJson(this.mPebbleAndroidInfo)).append("\n\n");
        }
        if (this.mLastDeviceRecord != null) {
            summary.append("Last connected device info:\n\n");
            summary.append(gson.toJson(this.mLastDeviceRecord)).append("\n\n");
        }
        return summary.toString();
    }

    static boolean isExternalStorageWritable() {
        return Environment.getExternalStorageState().equals("mounted");
    }

    private void fetchCoreDump() {
        PblFrameworkInterface frameworkInterface = PebbleApplication.getFrameworkInterface();
        PblDeviceRecord lastDeviceRecord = loadLastConnectedDeviceRecord();
        if (lastDeviceRecord.isEmpty()) {
            Trace.error(TAG, "No core dump can be returned, no connected devices");
            synchronized (this) {
                this.mHasCoreDump = Boolean.valueOf(false);
                this.mComplete = isComplete();
            }
            new CreateSupportAttachmentAsyncTask().submit();
            return;
        }
        frameworkInterface.requestCoreDump(lastDeviceRecord.pblDevice);
        FrameworkEventReceiver.registerFrameworkStateEventListener(new IFrameworkEventListener() {
            public void onFrameworkStateChanged(FrameworkState newState) {
                if (newState != null && newState.getLastEvent() != null && newState.getLastEvent() == EventType.CORE_DUMP_COMPLETE) {
                    boolean hasCoreDump;
                    CoreDumpResult result = CoreDumpResult.fromValue(newState.getCoreDumpResult());
                    if (result != CoreDumpResult.SUCCESS) {
                        Trace.debug(SupportEmail.TAG, "Core dump not returned: " + result);
                        hasCoreDump = false;
                    } else {
                        hasCoreDump = true;
                        SupportEmail.this.mCoreDumpFilename = newState.getCoreDumpFilename();
                    }
                    FrameworkEventReceiver.unregisterFrameworkStateEventListener(this);
                    synchronized (SupportEmail.this) {
                        SupportEmail.this.mHasCoreDump = Boolean.valueOf(hasCoreDump);
                        SupportEmail.this.mComplete = SupportEmail.this.isComplete();
                    }
                    SupportEmail.this.sendPing();
                    new CreateSupportAttachmentAsyncTask().submit();
                }
            }
        });
    }

    private void fetchLogDump() {
        Trace.verbose(TAG, "fetchLogDump()");
        PblFrameworkInterface frameworkInterface = PebbleApplication.getFrameworkInterface();
        PblDeviceRecord lastDeviceRecord = loadLastConnectedDeviceRecord();
        if (lastDeviceRecord.isEmpty()) {
            Trace.error(TAG, "No device logs or core dumps can be returned, no connected devices");
            synchronized (this) {
                this.mHasLogDump = Boolean.valueOf(false);
                this.mHasCoreDump = Boolean.valueOf(false);
                this.mComplete = isComplete();
            }
            new CreateSupportAttachmentAsyncTask().submit();
            return;
        }
        frameworkInterface.requestLogDump(lastDeviceRecord.pblDevice);
        FrameworkEventReceiver.registerFrameworkStateEventListener(new IFrameworkEventListener() {
            public void onFrameworkStateChanged(FrameworkState newState) {
                if (newState != null && newState.getLastEvent() != null) {
                    if (newState.getLastEvent() == EventType.LOG_DUMP_COMPLETE) {
                        boolean hasLogDump;
                        Trace.debug(SupportEmail.TAG, "Log dump complete");
                        Result result = Result.fromValue(newState.getLogDumpResult());
                        if (result != Result.SUCCESS) {
                            Trace.debug(SupportEmail.TAG, "Log dump not returned: " + result);
                            hasLogDump = false;
                        } else {
                            hasLogDump = true;
                            SupportEmail.this.mLogDumpFilename = newState.getLogDumpFilename();
                        }
                        FrameworkEventReceiver.unregisterFrameworkStateEventListener(this);
                        synchronized (SupportEmail.this) {
                            SupportEmail.this.mHasLogDump = Boolean.valueOf(hasLogDump);
                            SupportEmail.this.mComplete = SupportEmail.this.isComplete();
                        }
                        SupportEmail.this.sendPing();
                        SupportEmail.this.fetchCoreDump();
                    } else if (newState.getLastEvent() == EventType.LOG_CORE_DUMP_PING) {
                        SupportEmail.this.sendPing();
                    }
                }
            }
        });
    }

    public ArrayList<Uri> getAttachmentUris() {
        ArrayList<Uri> attachments = new ArrayList();
        if (this.mHasCoreDump != null && this.mHasCoreDump.booleanValue()) {
            File coreDumpFile = new File(this.mCoreDumpFilename);
            if (coreDumpFile.exists()) {
                attachments.add(Uri.fromFile(coreDumpFile));
            } else {
                Trace.error(TAG, "Could not find core dump file.");
            }
        }
        if (this.mHasLogDump != null && this.mHasLogDump.booleanValue()) {
            File logDumpFile = new File(this.mLogDumpFilename);
            if (logDumpFile.exists()) {
                attachments.add(Uri.fromFile(logDumpFile));
            } else {
                Trace.error(TAG, "Could not find log dump file");
            }
        }
        return attachments;
    }

    static void mergeStreamsInOrder(InputStream[] logStreams, PrintStream outputStream, Callback callback) {
        int i;
        BufferedReader[] readers = new BufferedReader[logStreams.length];
        try {
            String[] nextLineForStream = new String[readers.length];
            for (i = 0; i < logStreams.length; i++) {
                readers[i] = new BufferedReader(new InputStreamReader(logStreams[i]));
            }
            int linesCount = 0;
            while (true) {
                int linesCount2 = linesCount + 1;
                if (linesCount % 3000 == 0) {
                    callback.onPing();
                }
                boolean anyLinesLeft = false;
                for (i = 0; i < readers.length; i++) {
                    if (nextLineForStream[i] == null) {
                        nextLineForStream[i] = readers[i].readLine();
                    }
                    if (nextLineForStream[i] != null) {
                        anyLinesLeft = true;
                    }
                }
                if (!anyLinesLeft) {
                    break;
                }
                int streamToUse = 0;
                i = 0;
                while (i < readers.length) {
                    if (nextLineForStream[i] != null && !PATTERN_LOG_ENTRY_WITH_TIMESTAMP.matcher(nextLineForStream[i]).matches()) {
                        streamToUse = i;
                        break;
                    }
                    if (i > 0) {
                        if (nextLineForStream[streamToUse] == null) {
                            streamToUse = i;
                        } else if (nextLineForStream[i] != null && nextLineForStream[i].compareTo(nextLineForStream[streamToUse]) < 0) {
                            streamToUse = i;
                        }
                    }
                    i++;
                }
                outputStream.println("[" + streamToUse + "] " + nextLineForStream[streamToUse]);
                nextLineForStream[streamToUse] = null;
                linesCount = linesCount2;
            }
            for (i = 0; i < readers.length; i++) {
                if (readers[i] != null) {
                    try {
                        readers[i].close();
                    } catch (Throwable e) {
                        Trace.info("Error closing reader " + i, e);
                    }
                }
            }
        } catch (Exception e2) {
            Trace.debug(TAG, "Error reading log files", e2);
            for (i = 0; i < readers.length; i++) {
                if (readers[i] != null) {
                    try {
                        readers[i].close();
                    } catch (Throwable e3) {
                        Trace.info("Error closing reader " + i, e3);
                    }
                }
            }
        } catch (Throwable th) {
            for (i = 0; i < readers.length; i++) {
                if (readers[i] != null) {
                    try {
                        readers[i].close();
                    } catch (Throwable e32) {
                        Trace.info("Error closing reader " + i, e32);
                    }
                }
            }
        }
    }

    private static void filesToStreamInOrder(String[] logFiles, PrintStream outputStream, Callback callback) {
        if (AndroidLogger.acquireLogFileLock()) {
            try {
                int INDEX_SYSTEM_LOGCAT = logFiles.length;
                InputStream[] inputStreams = new InputStream[(logFiles.length + 1)];
                for (int i = 0; i < inputStreams.length; i++) {
                    if (i == INDEX_SYSTEM_LOGCAT) {
                        inputStreams[i] = Runtime.getRuntime().exec("logcat -v threadtime -d PebbleApplication:S").getInputStream();
                    } else {
                        inputStreams[i] = new FileInputStream(logFiles[i]);
                    }
                }
                Trace.verbose(TAG, "filesToStreamInOrder start");
                mergeStreamsInOrder(inputStreams, outputStream, callback);
                Trace.verbose(TAG, "filesToStreamInOrder finish");
            } catch (Exception e) {
            } finally {
                AndroidLogger.releaseLogFileLock();
            }
        } else {
            Trace.debug(TAG, "Could not acquire file lock; not truncating");
        }
    }

    static File createSupportAttachment(Context context, String summary, boolean includeLogs, String accountId, Callback callback) {
        PrintStream printStream;
        Exception e;
        Throwable th;
        File prevFile = getSupportAttachmentFile(context);
        if (prevFile.exists() && !FileUtil.delete(prevFile)) {
            Trace.warning(TAG, "Unable to delete previous support attachment file");
        }
        File file = getSupportAttachmentFile(context);
        if (isExternalStorageWritable()) {
            try {
                file.deleteOnExit();
                printStream = new PrintStream(new GZIPOutputStream(new FileOutputStream(file)));
                try {
                    catSupportAttachmentToStream(printStream, context, summary, includeLogs, accountId, callback);
                    if (printStream == null) {
                        return file;
                    }
                    printStream.flush();
                    printStream.close();
                    return file;
                } catch (Exception e2) {
                    e = e2;
                    try {
                        Trace.error(TAG, "Unhandled exception thrown when creating support attachment", e);
                        if (printStream != null) {
                            return file;
                        }
                        printStream.flush();
                        printStream.close();
                        return file;
                    } catch (Throwable th2) {
                        th = th2;
                        if (printStream != null) {
                            printStream.flush();
                            printStream.close();
                        }
                        throw th;
                    }
                }
            } catch (Exception e3) {
                e = e3;
                printStream = null;
                Trace.error(TAG, "Unhandled exception thrown when creating support attachment", e);
                if (printStream != null) {
                    return file;
                }
                printStream.flush();
                printStream.close();
                return file;
            } catch (Throwable th3) {
                th = th3;
                printStream = null;
                if (printStream != null) {
                    printStream.flush();
                    printStream.close();
                }
                throw th;
            }
        }
        Trace.info(TAG, "Unable to get support attachment, external storage not writable");
        return null;
    }

    static void catSupportAttachmentToStream(PrintStream printStream, Context context, String summary, boolean includeLogs, String accountId, Callback callback) {
        printStream.println("\n# Device info:");
        printStream.println("\nAccount: " + accountId);
        printStream.print(summary);
        printStream.println("\n# BT Apps:");
        printStream.print(getInstalledBluetoothApps(context.getPackageManager()));
        printStream.println("\n# Installed Pebble Apps:");
        PblInstalledAppDataModel.catInstalledAppsToStream(context.getContentResolver(), printStream);
        if (includeLogs) {
            String uiLogs = AndroidLogger.getLogFile(context, PebbleProcess.UI);
            String frameworkLogs = AndroidLogger.getLogFile(context, PebbleProcess.FRAMEWORK);
            printStream.println("\n# Phone logs:");
            filesToStreamInOrder(new String[]{uiLogs, frameworkLogs}, printStream, callback);
        }
        printStream.println("\n# Phone files:");
        catFileListToStream(printStream, context);
        printStream.println("\n# Preferences:");
        PreferenceModel.catPreferencesToStream(context.getContentResolver(), printStream);
        printStream.println("\n# Boot config:");
        BootConfig bootConfig = PebbleApplication.getBootConfig();
        if (bootConfig == null) {
            printStream.println("\n# <not available>");
            Trace.info(TAG, "bootConfig is null");
            return;
        }
        bootConfig.catBootConfigToStream(printStream);
    }

    private static File getSupportAttachmentFile(Context context) {
        return new File(context.getExternalFilesDir(null), "pebble.log.gz");
    }

    private static String getInstalledBluetoothApps(PackageManager packageManager) {
        if (packageManager == null) {
            Trace.debug(TAG, "Cannot fetch Bluetooth apps with null package manager");
            return "";
        }
        Object btEnabledPackages = new HashSet();
        List<ApplicationInfo> applicationInfoList = packageManager.getInstalledApplications(128);
        if (applicationInfoList == null) {
            Trace.debug(TAG, "ApplicationInfoList is null");
            return "";
        }
        for (ApplicationInfo applicationInfo : applicationInfoList) {
            try {
                String[] requestedPermissions = packageManager.getPackageInfo(applicationInfo.packageName, 4096).requestedPermissions;
                if (requestedPermissions != null) {
                    for (String perm : requestedPermissions) {
                        if ("android.permission.BLUETOOTH".equals(perm) || "android.permission.BLUETOOTH_ADMIN".equals(perm)) {
                            btEnabledPackages.add(applicationInfo.packageName);
                            break;
                        }
                    }
                }
            } catch (NameNotFoundException e) {
                Trace.error(TAG, "Failed to find package", e);
            }
        }
        return new GsonBuilder().setPrettyPrinting().create().toJson(btEnabledPackages);
    }

    private static void catFileListToStream(PrintStream printStream, Context context) {
        dumpFileUsageToStream(context.getExternalFilesDir(null), printStream);
        dumpFileUsageToStream(context.getFilesDir(), printStream);
        dumpFileUsageToStream(context.getCacheDir(), printStream);
        dumpFileUsageToStream(context.getDir("logs", 0), printStream);
    }

    private static void dumpFileUsageToStream(File dir, final PrintStream out) {
        if (dir == null) {
            Trace.warning(TAG, "null dir to dump");
        } else if (out == null) {
            Trace.warning(TAG, "Null output stream");
        } else {
            Trace.debug(TAG, "walking.. " + dir.toString());
            try {
                FileUtil.walk(dir, new FileFoundCallback() {
                    public void directoryFound(File file) {
                        out.println("Dir: " + file.getAbsoluteFile());
                    }

                    public void fileFound(File file) {
                        out.println("File: " + file.getAbsoluteFile() + " Size: " + file.length() + " Modified: " + DateFormat.getDateTimeInstance().format(new Date(file.lastModified())));
                    }
                });
            } catch (Throwable e) {
                Trace.error(TAG, e);
            }
        }
    }
}
